package com.congee02.aop;

import com.congee02.aop.proxy.dynamic.Executable;
import com.congee02.aop.proxy.dynamic.Execution;
import com.congee02.aop.proxy.dynamic.FlexibleDynamicProxyFactory;
import com.congee02.aop.service.UserService;
import com.congee02.aop.service.UserServiceImpl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author congee(congee02 @ 163.com)
 * @date 1/26/2023 4:41 PM
 */
public class AopTest {

    /**
     * Advice 种类
     */
    private static final String BEFORE = "before", AFTER = "after";

    /**
     * 模拟简单的 IoC 容器
     */
    private static Map<String, Object> map = new HashMap<>();

    /**
     * 在 ioc 容器中新增一个 bean
     * @param name bean 的名称
     * @param o bean
     */
    public static void addBean(String name, Object o) {
        map.put(name, o);
    }

    /**
     * 使用 aop 增强一个 bean
     * @param name bean 的名称
     * @param e 执行过程
     * @param type  advice 类型
     */
    public static void addAdvice(String name, Executable e, String type) {

        Object o = map.get(name);


        FlexibleDynamicProxyFactory factory = new FlexibleDynamicProxyFactory(o, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                // before advice
                if (BEFORE.equals(type)) {
                    e.execute();
                }

                Object retValue = method.invoke(o, args);

                // after advice
                if (AFTER.equals(type)) {
                    e.execute();
                }


                return retValue;
            }
        });

        map.put(name, factory.getProxyInstance());

    }

    public static void main(String[] args) throws NoSuchMethodException {

        final String arg = "congee02";

        UserServiceImpl service = new UserServiceImpl();

        addBean("userService", service);

        System.out.println("=====无 AOP 增强=====");
        ((UserService) map.get("userService")).save(arg);

        // 切面类
        UserServiceAspect aspect = new UserServiceAspect();

        System.out.println("=====日志=====");
        Execution beforeLog =
                new Execution(aspect, "log", new Class[]{String.class} ,new Object[]{arg});
        addAdvice("userService", beforeLog, BEFORE);
        ((UserService) map.get("userService")).save(arg);

        System.out.println("=====日志，唤醒=====");
        Execution afterNotify = new Execution(aspect, "notify", new Class[]{String.class}, new Object[]{arg});
        addAdvice("userService", afterNotify, AFTER);
        ((UserService) map.get("userService")).save(arg);


    }

}
